package util;

/**
 * CRC8位校验
 *
 * @author wanglei
 * @date 2021/6/7
 */
public class CRC8Util{

    // 测试
    public static void main(String[] args) {
        String str = "B3 65 28 01 7F 51 C0 01 00 51 59 10 05 06 21 58 52 05 00 00 95 68 00 00 00 59 36 04 00 00 85 21 03 00 00 29 56 07 00 00 53 21 06 00 00 53 21 06 00 00 00 00 24 0D 00 55 24 08 42 5A 4A 4B 2D 32 30 30 32 31 36 30 31 30 31 30 30 31 C7";
        String[] ss = str.split(" ");
        byte[] bs = new byte[ss.length];
        int i=0;
        for(String s : ss){
            byte b = HexUtil.str2byte(s);
            bs[i] = b;
            i++;
        }
        int b = CRC8_ROHC(bs, 0, ss.length);
        System.out.println(Integer.toHexString(b));
    }

    /**
     * CRC-8
     *
     * <table width="400px" border="1" cellpadding="0" cellspacing="0">
     *     <tr>
     *         <th>多项式</th>
     *         <th>初始值</th>
     *         <th>异或值</th>
     *         <th>Bit反转</th>
     *     </tr>
     *     <tr>
     *         <td align="center">0x07</td>
     *         <td align="center">0x00</td>
     *         <td align="center">0x00</td>
     *         <td align="center">MSB First</td>
     *     </tr>
     * </table>
     *
     * @param  source
     * @param  offset
     * @param  length
     * @return
     */
    public static int CRC8(byte[] source, int offset, int length) {
        int wCRCin = 0x00;
        int wCPoly = 0x07;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            for (int j = 0; j < 8; j++) {
                boolean bit = ((source[i] >> (7 - j) & 1) == 1);
                boolean c07 = ((wCRCin >> 7 & 1) == 1);
                wCRCin <<= 1;
                if (c07 ^ bit)
                    wCRCin ^= wCPoly;
            }
        }
        wCRCin &= 0xFF;
        return wCRCin;
    }

    /**
     * CRC-8/76520
     * X7+X6+X5+X2+1,
     * 多项式POLY（Hex）：0xe5
     * 初始值INT（Hex）：00
     * 结果异或值 XOROUT（Hex）：00
     * 输入数据和输出数据不做反转
     *
     * @author wanglei
     * @date 2021/6/7
     * */
    public static int CRC8_76520(byte[] source, int offset, int length) {
        int wCRCin = 0x00;
        int wCPoly = 0xe5;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            for (int j = 0; j < 8; j++) {
                boolean bit = ((source[i] >> (7 - j) & 1) == 1);
                boolean c07 = ((wCRCin >> 7 & 1) == 1);
                wCRCin <<= 1;
                if (c07 ^ bit)
                    wCRCin ^= wCPoly;
            }
        }
        wCRCin &= 0xFF;
        return wCRCin;
    }

    /**
     * CRC-8/DARC
     *
     * <table width="400px" border="1" cellpadding="0" cellspacing="0">
     *     <tr>
     *         <th>多项式</th>
     *         <th>初始值</th>
     *         <th>异或值</th>
     *         <th>Bit反转</th>
     *     </tr>
     *     <tr>
     *         <td align="center">0x39</td>
     *         <td align="center">0x00</td>
     *         <td align="center">0x00</td>
     *         <td align="center">LSB First</td>
     *     </tr>
     * </table>
     *
     * @param  source
     * @param  offset
     * @param  length
     * @return
     */
    public static int CRC8_DARC(byte[] source, int offset, int length) {
        int wCRCin = 0x00;
        int wCPoly = 0x9C;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            wCRCin ^= ((long) source[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((wCRCin & 0x01) != 0) {
                    wCRCin >>= 1;
                    wCRCin ^= wCPoly;
                } else {
                    wCRCin >>= 1;
                }
            }
        }
        return wCRCin ^= 0x00;
    }

    /**
     * CRC-8/ITU
     *
     * <table width="400px" border="1" cellpadding="0" cellspacing="0">
     *     <tr>
     *         <th>多项式</th>
     *         <th>初始值</th>
     *         <th>异或值</th>
     *         <th>Bit反转</th>
     *     </tr>
     *     <tr>
     *         <td align="center">0x07</td>
     *         <td align="center">0x00</td>
     *         <td align="center">0x55</td>
     *         <td align="center">MSB First</td>
     *     </tr>
     * </table>
     *
     * @param  source
     * @param  offset
     * @param  length
     * @return
     */
    public static int CRC8_ITU(byte[] source, int offset, int length) {
        int wCRCin = 0x00;
        int wCPoly = 0x07;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            for (int j = 0; j < 8; j++) {
                boolean bit = ((source[i] >> (7 - j) & 1) == 1);
                boolean c07 = ((wCRCin >> 7 & 1) == 1);
                wCRCin <<= 1;
                if (c07 ^ bit)
                    wCRCin ^= wCPoly;
            }
        }
        wCRCin &= 0xFF;
        return wCRCin ^= 0x55;
    }

    /**
     * CRC-8/MAXIM
     *
     * <table width="400px" border="1" cellpadding="0" cellspacing="0">
     *     <tr>
     *         <th>多项式</th>
     *         <th>初始值</th>
     *         <th>异或值</th>
     *         <th>Bit反转</th>
     *     </tr>
     *     <tr>
     *         <td align="center">0x31</td>
     *         <td align="center">0x00</td>
     *         <td align="center">0x00</td>
     *         <td align="center">LSB First</td>
     *     </tr>
     * </table>
     *
     * @param  source
     * @param  offset
     * @param  length
     * @return
     */
    public static int CRC8_MAXIM(byte[] source, int offset, int length) {
        int wCRCin = 0x00;
        // Integer.reverse(0x31) >>> 24
        int wCPoly = 0x8C;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            wCRCin ^= ((long) source[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((wCRCin & 0x01) != 0) {
                    wCRCin >>= 1;
                    wCRCin ^= wCPoly;
                } else {
                    wCRCin >>= 1;
                }
            }
        }
        return wCRCin ^= 0x00;
    }

    /**
     * CRC-8/ROHC
     *
     * <table width="400px" border="1" cellpadding="0" cellspacing="0">
     *     <tr>
     *         <th>多项式</th>
     *         <th>初始值</th>
     *         <th>异或值</th>
     *         <th>Bit反转</th>
     *     </tr>
     *     <tr>
     *         <td align="center">0x07</td> 多项式
     *         <td align="center">0xFF</td> 初始值
     *         <td align="center">0x00</td> 结果异或值
     *         <td align="center">LSB First</td>
     *     </tr>
     * </table>
     *
     * @param  source
     * @param  offset
     * @param  length
     * @return
     */
    public static int CRC8_ROHC(byte[] source, int offset, int length) {
        int wCRCin = 0xFF;
        int wCPoly = 0xE0;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            wCRCin ^= ((long) source[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((wCRCin & 0x01) != 0) {
                    wCRCin >>= 1;
                    wCRCin ^= wCPoly;
                } else {
                    wCRCin >>= 1;
                }
            }
        }
        return wCRCin;
    }

}
